/*
Name: Hemanth. B
Website: java-swing-tutorial.html

Topic: A basic Java Swing Calculator

Conventions Used in Source code
---------------------------------
1. All JLabel components start with jlb*
2. All JPanel components start with jpl*
3. All JMenu components start with jmenu*
4. All JMenuItem components start with jmenuItem*
5. All JDialog components start with jdlg*
6. All JButton components start with jbn*
 */
package exercises.day04.pt01.calculator;

import java.util.ArrayList;

public class Calculator {
    // Variables

    //memory store array of numbers
    private static ArrayList<Double> memory = new ArrayList<Double>();
    private static int memoryIndex = 0;
    //lenght of number
    final int MAX_INPUT_LENGTH = 20;
    //input, result, error mode
    final int INPUT_MODE = 0;
    final int RESULT_MODE = 1;
    final int ERROR_MODE = 2;
    //what mode is on
    int displayMode;
    //if cleardigit
    boolean clearOnNextDigit;
    //current number aka result
    double lastNumber;
    //checks operator
    String lastOperator = "0";
    //screen display string
    private static String display = "";

    // Constructor 
    public Calculator() {
    }

    //get number entered and add to current string screen
    public static void setDisplay(String display) {
        Calculator.display = display;
    }

    /**
     * calculate sqaureroot
     */
    public void squareroot() {
        double result = 0;
        if (displayMode != ERROR_MODE) {
            try {
                //if negative sign with no number
                if (getDisplayString().indexOf("-") == 0) {
                    displayError("Invalid input for function!");
                }
                //calculate sqrt
                result = Math.sqrt(getNumberInDisplay());
                //add to current number aka result
                displayResult(result);
            } catch (Exception ex) {
                displayError("Invalid input for function!");
                displayMode = ERROR_MODE;
            }
        }
    }

    /**
     * calculate fraction
     */
    public void fraction() {
        double result = 0;
        if (displayMode != ERROR_MODE) {
            try {
                if (getNumberInDisplay() == 0) {
                    displayError("Cannot divide by zero!");
                }

                result = 1 / getNumberInDisplay();
                displayResult(result);
            } catch (Exception ex) {
                displayError("Cannot divide by zero!");
                displayMode = ERROR_MODE;
            }
        }
    }

    /**
     * remove most current number from display
     */
    public void backspace() {
        if (displayMode != ERROR_MODE) {
            setDisplayString(getDisplayString().substring(0,
                    getDisplayString().length() - 1));

            if (getDisplayString().length() < 1) {
                setDisplayString("0");
            }
        }
    }

    /**
     * calculate percent aka /100
     */
    public void percent() {
        double result = 0;
        if (displayMode != ERROR_MODE) {
            try {
                result = getNumberInDisplay() / 100;
                displayResult(result);
            } catch (Exception ex) {
                displayError("Invalid input for function!");
                displayMode = ERROR_MODE;
            }
        }
    }

    /**
     * add to current display
     *
     * @param s
     */
    public void setDisplayString(String s) {
        Calculator.display = s;
    }

    /**
     * get screen
     *
     * @return screen display
     */
    public String getDisplayString() {
        return Calculator.display;
    }

    /**
     * add number to display
     *
     * @param digit
     */
    public void addDigitToDisplay(int digit) {
        if (clearOnNextDigit) {
            setDisplayString("");
        }

        String inputString = getDisplayString();

        if (inputString.indexOf("0") == 0) {
            inputString = inputString.substring(1);
        }

        if ((!inputString.equals("0") || digit > 0)
                && inputString.length() < MAX_INPUT_LENGTH) {
            setDisplayString(inputString + digit);
        }


        displayMode = INPUT_MODE;
        clearOnNextDigit = false;
    }

    /**
     * adds a decimal pointto current number
     */
    public void addDecimalPoint() {
        displayMode = INPUT_MODE;

        if (clearOnNextDigit) {
            setDisplayString("");
        }

        String inputString = getDisplayString();

        // If the input string already contains a decimal point, don't
        //  do anything to it.
        if (inputString.indexOf(".") < 0) {
            setDisplayString(new String(inputString + "."));
        }
    }

    /**
     * adds plus or minus sign
     */
    public void processSignChange() {
        if (displayMode == INPUT_MODE) {
            String input = getDisplayString();

            if (input.length() > 0 && !input.equals("0")) {
                if (input.indexOf("-") == 0) {
                    setDisplayString(input.substring(1));
                } else {
                    setDisplayString("-" + input);
                }
            }

        } else if (displayMode == RESULT_MODE) {
            double numberInDisplay = getNumberInDisplay();

            if (numberInDisplay != 0) {
                displayResult(-numberInDisplay);
            }
        }
    }

    /**
     * clear all except memory
     */
    public void clearAll() {
        setDisplayString("0");
        lastOperator = "0";
        lastNumber = 0;
        displayMode = INPUT_MODE;
        clearOnNextDigit = true;
    }

    /**
     * clear existing number
     */
    public void clearExisting() {
        setDisplayString("0");
        clearOnNextDigit = true;
        displayMode = INPUT_MODE;
    }

    /**
     * gets number to display
     *
     * @return number to display
     */
    public double getNumberInDisplay() {
        String input = Calculator.display;
        return Double.parseDouble(input);
    }

    /**
     * add, subtract, divide, multiply processor
     *
     * @param op
     */
    public void processOperator(String op) {
        if (displayMode != ERROR_MODE) {
            double numberInDisplay = getNumberInDisplay();

            if (!lastOperator.equals("0")) {
                try {
                    double result = processLastOperator();
                    displayResult(result);
                    lastNumber = result;
                } catch (DivideByZeroException e) {
                }
            } else {
                lastNumber = numberInDisplay;
            }

            clearOnNextDigit = true;
            lastOperator = op;
        }
    }

    /**
     * whatever is equal to
     */
    public void processEquals() {
        double result = 0;

        if (displayMode != ERROR_MODE) {
            try {
                result = processLastOperator();
                displayResult(result);
            } catch (DivideByZeroException e) {
                displayError("Cannot divide by zero!");
            }

            lastOperator = "0";
        }
    }

    /**
     * gets operator and process accordingly
     *
     * @return
     * @throws exercises.day04.pt01.calculator.Calculator.DivideByZeroException
     */
    public double processLastOperator() throws DivideByZeroException {
        double result = 0;
        double numberInDisplay = getNumberInDisplay();

        if (lastOperator.equals("/")) {
            if (numberInDisplay == 0) {
                throw (new DivideByZeroException());
            }

            result = lastNumber / numberInDisplay;
        }

        if (lastOperator.equals("*")) {
            result = lastNumber * numberInDisplay;
        }

        if (lastOperator.equals("-")) {
            result = lastNumber - numberInDisplay;
        }

        if (lastOperator.equals("+")) {
            result = lastNumber + numberInDisplay;
        }

        return result;
    }

    /**
     * display results
     *
     * @param result
     */
    public void displayResult(double result) {
        setDisplayString(Double.toString(result));
        lastNumber = result;
        displayMode = RESULT_MODE;
        clearOnNextDigit = true;
    }

    /**
     * display error message in screen
     *
     * @param errorMessage
     */
    public void displayError(String errorMessage) {
        setDisplayString(errorMessage);
        lastNumber = 0;
        displayMode = ERROR_MODE;
        clearOnNextDigit = true;
    }

    //End of Swing Calculator Class.
    private class DivideByZeroException extends Exception {

        public DivideByZeroException() {
            super();
        }

        public DivideByZeroException(String s) {
            super(s);
        }
    }

    public void memoryRemove() {
        try {
            memory.remove(display);
            System.out.println("removed successfully");
            memoryIndex--;
        } catch (Exception ex) {
            System.out.println("Memory removal invalid");
        }


    }

    public void memoryAdd() {
        try {
            memory.add(Double.valueOf(display));

            System.out.println("added successfully");
        } catch (NumberFormatException ex) {
            displayError("Invalid input for to memory!");
            displayMode = ERROR_MODE;
        }

    }

    public void memoryClear() {
        memory.clear();
        System.out.println("cleared successfully");
    }

    public void memoryNext() {
        memoryIndex++;
        if (memoryIndex <= memory.size() - 1 && memoryIndex >= 0) {
            System.out.println(memoryIndex + " " + memory.get(memoryIndex).toString());
            setDisplayString(memory.get(memoryIndex).toString());
            System.out.println(memoryIndex + "-" + memory.get(memoryIndex).toString());

        }

    }

    public void memoryPrevious() {

        memoryIndex--;
        if (memoryIndex <= memory.size() - 1 && memoryIndex >= 0) {
            System.out.println(memoryIndex + " " + memory.get(memoryIndex).toString());
            setDisplayString(memory.get(memoryIndex).toString());
            System.out.println(memoryIndex + "-" + memory.get(memoryIndex).toString());


        }

    }
}